package cn.itsource.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.itsource.constants.Constants;
import cn.itsource.constants.GlobalExceptionCode;
import cn.itsource.exception.GlobalException;
import cn.itsource.mapper.PermissionMapper;
import cn.itsource.pojo.domain.Login;
import cn.itsource.mapper.LoginMapper;
import cn.itsource.pojo.dto.AdminDto;
import cn.itsource.pojo.dto.WechatLoginResult;
import cn.itsource.pojo.vo.LoginVo;
import cn.itsource.pojo.vo.SharedLoginVo;
import cn.itsource.service.ILoginService;
import cn.itsource.template.WechatTemplate;
import cn.itsource.utils.AssertUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.beans.Beans;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 登录表 服务实现类
 * </p>
 *
 * @author beishan
 * @since 2024-03-29
 */
@Service
@Slf4j
@Transactional
public class LoginServiceImpl extends ServiceImpl<LoginMapper, Login> implements ILoginService {

    @Autowired
    private WechatTemplate wechatTemplate;

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Autowired
    private PermissionMapper permissionMapper;


    @Autowired
    private  PasswordEncoder passwordEncoder;

    @Autowired
    private LoginMapper loginMapper;

    /**
     * 管理员登录
     * @param adminDto 用户密码
     */
    @Override
    public LoginVo adminLogin(AdminDto adminDto) {

        Login admin = super.getOne(new LambdaQueryWrapper<Login>().eq(Login::getUsername, adminDto.getUsername()));
        AssertUtil.isNotNull(admin, GlobalExceptionCode.ADMIN_USERNAME_ERROR);

        if (!passwordEncoder.matches(adminDto.getPassword(), admin.getPassword())){
            throw new GlobalException(GlobalExceptionCode.ADMIN_PASSWORD_ERROR);
        }
        //判断是否是管理员
        if (admin.getType() != Constants.Login.TYPE_ADMIN && !admin.getEnabled()) {
            throw new GlobalException(GlobalExceptionCode.NO_PERMISSION);
        }

        return SaTokenLogin(admin);

    }

    @Override
    public void delById(Long id) {
        loginMapper.delById(id);
    }


    /**
     * 微信登录
     * @param loginResult 微信授权码
     * @return
     */
    @Override
    public LoginVo wechatLogin(WechatLoginResult loginResult) {
        //获取openid
        String openid = wechatTemplate.getOpenid(loginResult.getWxCode());
        //通过openid 去查询数据库
        Login one = super.getOne(new LambdaQueryWrapper<Login>().eq(Login::getOpenId, openid)
                .eq(Login::getEnabled,true)
                .and(a -> a.eq(Login::getType, Constants.Login.TYPE_DRIVER)));
        //判断one 是否为空
        if (one == null) {
            //为空抛出异常
            throw new GlobalException("该微信未注册");
        }


        return SaTokenLogin(one);
    }

    public LoginVo SaTokenLogin(Login one){
        //不为空  执行satoken登录 注册
        StpUtil.login(one.getId());
        //传入id 获取权限
        permissions2redisById(one.getId());
        //获取satoken
        String tokenValue = StpUtil.getTokenValue();
        //封装相关参数 并返回
        LoginVo loginVo = new LoginVo();
        loginVo.setSatoken(tokenValue);
        loginVo.setPermissions(permissions2redisById(one.getId()));
        SharedLoginVo root = new SharedLoginVo(one.getNickName(), one.getAvatar(), one.getPhone(), "Root");
        loginVo.setLogin(root);
        //登录时将相关数据 保存到redis
        String format = String.format(Constants.Redis.REG_INFO, one.getId());
        redisTemplate.opsForValue().set(format, root);

        log.info("登录satoken -{}",tokenValue);
        return loginVo;
    }


    /**
     * 通过id查询权限 并存放在redis
     * @param id 登录人的id
     */
    public List<String> permissions2redisById(Long id){
        List<String>  redisResult = permissionMapper.permissions2redisById(id);
        log.info("查询的权限- {}" ,redisResult);
        String permissionId = Constants.Redis.PERMISSIONS_ID.formatted(id);
        redisTemplate.opsForValue().set(permissionId,redisResult);
        return redisResult;
    }
}
